home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
emerald
/
emrldsys.lha
/
Language
/
Compiler
/
environment.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-16
|
19KB
|
729 lines
/*
* @(#)environment.c 1.7 4/20/88
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include "assert.h"
#include "scan.h"
#include "nodes.h"
#include "error.h"
#include "opNames.h"
#include "flags.h"
#include "system.h"
#include <errno.h>
#include "sequence.h"
#include "semantics.h"
#include "map.h"
#include "builtins.h"
#include "environment.h"
#include "trace.h"
void resolveGlobal();
extern NodePtr findObjectOperation();
extern void myLink();
#undef NULL
#include "ndbm.h"
#undef NULL
#define NULL 0
extern char *emDirectory;
extern char *emdbDirectory;
extern DBM *emDBM;
typedef struct sEnvironRecord {
OID id;
struct sEnvironRecord *next;
} EnvironRecord, *EnvironRecordPtr;
static EnvironRecordPtr writeHead = NULL;
static EnvironRecordPtr readHead = NULL;
Map environmentMap = NULL;
Map objectTable;
Map translateOIDMap = NULL;
extern NodePtr loadObject(), readTree();
extern void storeObject(), writeTree();
char *makeOIDFileName(), *makeOIDDotoFileName();
void initializeEnvironment()
{
objectTable = Map_Create();
environmentMap = Map_Create();
if (bflag) translateOIDMap = Map_Create();
}
void scheduleOutput(id)
OID id;
{
EnvironmentStage stage;
EnvironRecordPtr p;
stage = (EnvironmentStage) Map_Lookup(environmentMap, (int)id);
if (stage == E_Imported) return;
else if (stage == E_Exported) return;
else if (stage == E_ScheduledExport) return;
assert(stage != E_ScheduledImport);
assert((int)stage == NIL);
p = (EnvironRecordPtr)malloc(sizeof(EnvironRecord));
p->id = id;
p->next = writeHead;
writeHead = p;
Map_Insert(environmentMap, (int)id, (int) E_ScheduledExport);
}
/*
* This one runs through the list of things to write, and writes each of them
* in turn. When writeTree writes a globalreference, it calls scheduleOutput
* to ensure that the object has been written out.
*/
void doOutput()
{
EnvironRecordPtr p;
while (writeHead != NULL) {
p = writeHead;
writeHead = writeHead->next;
storeObject(p->id);
free((char *) p);
}
}
Boolean environmentWasImported(id)
OID id;
{
EnvironmentStage stage;
stage = (EnvironmentStage) Map_Lookup(environmentMap, (int)id);
if (stage == E_Imported) return(TRUE);
if (stage == E_ScheduledImport) assert(FALSE);
return(FALSE);
}
void scheduleInput(id)
OID id;
{
EnvironmentStage stage;
EnvironRecordPtr p;
stage = (EnvironmentStage) Map_Lookup(environmentMap, (int)id);
if (stage == E_Imported) return;
if (stage == E_ScheduledImport) return;
assert(stage != E_Exported);
assert(stage != E_ScheduledExport);
assert((int)stage == NIL);
p = (EnvironRecordPtr)malloc(sizeof(EnvironRecord));
p->id = id;
p->next = readHead;
readHead = p;
Map_Insert(environmentMap, (int)id, (int) E_ScheduledImport);
TRACE1(environment, 5, "Scheduling input of 0x%08x", id);
}
void doInput()
{
EnvironRecordPtr p;
while (readHead != NULL) {
p = readHead;
readHead = readHead->next;
(void) loadObject(p->id);
free((char *) p);
}
}
static Map gMap;
static Boolean doScheduleInput = FALSE;
static void r_scanForGlobals(p)
register NodePtr p;
{
register NodePtr q;
register Symbol st;
OID id;
if ((int) p <= 0x200) return;
if (Map_Lookup(gMap, (int)p) != NIL) return;
Map_Insert(gMap, (int)p, 1);
switch (p->tag) {
case P_GLOBALREF:
assert(p->b.globalref.value == NULL);
if (doScheduleInput && Map_Lookup(objectTable, (int)p->b.globalref.id) == NIL) {
scheduleInput(p->b.globalref.id);
}
break;
case P_OBLIT:
id = p->b.atlit.id;
if (id != 0) {
OTInsert(p, id);
Map_Insert(environmentMap, (int)id, (int)E_Imported);
}
id = getCodeOID(p);
if (id != 0) {
OTInsert(p, id);
Map_Insert(environmentMap, (int)id, (int)E_Imported);
}
break;
case P_ATLIT:
id = p->b.atlit.id;
if (id != 0) {
OTInsert(p, id);
Map_Insert(environmentMap, (int)id, (int)E_Imported);
}
break;
case P_SYMDEF:
case P_SYMREF:
st = ST_Fetch(p->b.symdef.symbol);
if (st->value.ATinfo != NULL) r_scanForGlobals(st->value.ATinfo);
if (st->value.CTinfo != NULL) r_scanForGlobals(st->value.CTinfo);
if (st->value.value != NULL) r_scanForGlobals(st->value.value);
break;
default:
break;
}
Sequence_For(q, p)
if ((int) q >= 0x200) r_scanForGlobals(q);
Sequence_Next
}
void scanForGlobals(p, dsi)
NodePtr p;
Boolean dsi;
{
gMap = Map_Create();
doScheduleInput = dsi;
r_scanForGlobals(p);
Map_Destroy(gMap);
}
NodePtr loadObject(id)
OID id;
{
char *theOIDFileName;
NodePtr s;
s = (NodePtr) Map_Lookup(objectTable, (int)id);
if ((int)s != NIL) {
TRACE1(environment, 5, "Already loaded 0x%08x", id);
} else {
Map_Insert(environmentMap, (int)id, (int)E_Imported);
theOIDFileName = makeOIDFileName(id);
TRACE1(environment, 5, "loading \"%s\"", theOIDFileName);
s = readTree(theOIDFileName);
free(theOIDFileName);
OTInsert(s, id);
/* Scan for global references. */
scanForGlobals(s, TRUE);
}
return(s);
}
void storeObject(id)
OID id;
{
NodePtr p;
char *theOIDFileName, *theSecondOIDFileName;
p = (NodePtr) Map_Lookup(objectTable, (int)id);
assert((int)p != NIL);
assert(p->tag == P_OBLIT || p->tag == P_ATLIT);
if (p->tag == P_OBLIT && p->b.oblit.codeOID == id && p->b.oblit.id != 0) {
scheduleOutput(p->b.oblit.id);
if (bflag) {
Map_Insert(environmentMap, (int)id, (int)E_Exported);
} else {
Map_Insert(environmentMap, (int)id, (int)E_Exported);
theOIDFileName = makeOIDFileName(p->b.oblit.id);
theSecondOIDFileName = makeOIDFileName(p->b.oblit.codeOID);
myLink(theOIDFileName, theSecondOIDFileName, TRUE, p);
free(theOIDFileName);
free(theSecondOIDFileName);
}
} else if (p->b.oblit.id != id && p->b.oblit.codeOID != id) {
/* something weird, ignore it */
Map_Insert(environmentMap, (int)id, (int)E_Exported);
} else {
theOIDFileName = makeOIDFileName(id);
TRACE2(environment, 2, "storeObject: writing 0x%08x to \"%s\"", id,
theOIDFileName);
Map_Insert(environmentMap, (int)id, (int)E_Exported);
writeTree(theOIDFileName, p);
free(theOIDFileName);
}
}
NodePtr OTLookup(id)
OID id;
{
register NodePtr q;
q = (NodePtr) Map_Lookup(objectTable, (int) id);
if (q == (NodePtr) NIL) {
TRACE1(environment, 1, "Trying to find object 0x%08x", id);
scheduleInput(id);
doInput();
}
q = (NodePtr) Map_Lookup(objectTable, (int) id);
assert(q != (NodePtr) NIL);
return(q);
}
void resolveGlobal(p, value)
register NodePtr p;
Value *value;
{
NodePtr q;
assert(p->tag == P_GLOBALREF);
q = p->b.globalref.value;
if (q == NULL) {
q = OTLookup(p->b.globalref.id);
assert((int)q != NIL);
p->b.globalref.value = q;
}
/* q is now the value */
if (value != NULL) {
if (q->tag == P_OBLIT) {
value->value = q;
value->CTinfo = q;
assert(q->b.oblit.myat != NULL);
value->ATinfo = q->b.oblit.myat;
} else if (q->tag == P_ATLIT) {
value->value = q;
value->ATinfo = refToBuiltin(B_INSTAT, SIGNATUREINDEX);
value->CTinfo = refToBuiltin(B_INSTCT, SIGNATUREINDEX);
}
}
}
void OTInsert(p, id)
register NodePtr p;
OID id;
{
TRACE2(environment, 5, "OTInsert: OID 0x%08x as 0x%x.", id, p);
Map_Insert(objectTable, (int) id, (int)p);
}
extern char *writeAT();
static char *ATInfo, thevaluespace[20];
static datum keydatum, valuedatum;
Boolean isPossibleAnswer(id, thekeydatum)
datum thekeydatum;
OID id;
{
char *treeFileName, *dotoFileName;
int sysresult;
struct stat statbuf;
Boolean theAnswer = TRUE;
if (Map_Lookup(objectTable, (int)id) != NIL) return(theAnswer);
treeFileName = makeOIDFileName(id);
dotoFileName = makeOIDDotoFileName(id);
sysresult = stat(treeFileName, &statbuf);
if (sysresult < 0) {
if (errno == ENOENT) {
TRACE1(matchat, 1, "no tree file %s", treeFileName);
TRACE1(invoccache, 3, "no tree file %s", treeFileName);
theAnswer = FALSE;
} else {
fprintf(stdout, "Cannot stat %s: %s", treeFileName,
errno < sys_nerr ? sys_errlist[errno] : "unknown reason");
exit(1);
}
}
if (!bflag && theAnswer) {
sysresult = stat(dotoFileName, &statbuf);
if (sysresult < 0) {
if (errno == ENOENT) {
TRACE1(matchat, 1, "no doto file %s", dotoFileName);
TRACE1(invoccache, 3, "no doto file %s", dotoFileName);
theAnswer = FALSE;
} else {
fprintf(stdout, "Cannot stat %s: %s", dotoFileName,
errno < sys_nerr ? sys_errlist[errno] : "unknown reason");
exit(1);
}
}
}
free(dotoFileName);
free(treeFileName);
if (!theAnswer) {
dbm_delete(emDBM, thekeydatum);
}
return(theAnswer);
}
OID isDuplicateAT(p)
register NodePtr p;
{
OID resultOID;
NodePtr anob;
if (p->tag != P_ATLIT ||
p->b.atlit.name == NULL ||
p->b.atlit.f.isTypeVariable ||
p->b.atlit.f.dependsOnTypeVariable) return(0);
ATInfo = writeAT(p, FALSE, FALSE);
if (ATInfo == NULL) {
TRACE0(matchat, 1, "Cannot write (not figure out yet) AT");
keydatum.dptr = NULL;
keydatum.dsize = 0;
return(0);
}
IFTRACE(matchat, 1) {
printf("%s: %s", ST_SymbolName(p->b.atlit.name->b.symdef.symbol), ATInfo);
}
TRACE1(matchat, 1, "EI: The key is %s", ATInfo);
keydatum.dptr = ATInfo;
keydatum.dsize = strlen(ATInfo);
valuedatum = dbm_fetch(emDBM, keydatum);
TRACE2(matchat, 1, "The result of fetch = \"%.*s\"", valuedatum.dsize,
valuedatum.dptr);
if (valuedatum.dptr != NULL) {
bcopy(valuedatum.dptr, thevaluespace, valuedatum.dsize);
*(thevaluespace+valuedatum.dsize) = '\0';
if (sscanf(thevaluespace, "O0x%x", &resultOID) != 1) assert(FALSE);
TRACE1(matchat, 1, "Found it, result OID 0x%08x", resultOID);
TRACE0(matchat, 1, "Checking the possiblity of the result");
if (! isPossibleAnswer(resultOID, keydatum)) {
TRACE0(matchat, 1, "That is not a possible answer.");
} else {
anob = OTLookup(resultOID);
TRACE2(matchat, 1, "Result object = 0x%08x %s", anob, ATName(anob));
free(ATInfo);
return(resultOID);
}
}
TRACE0(matchat, 1, "Did not find it.");
resultOID = 0;
return(resultOID);
}
extern void ensureGenerate();
void defineAT(p)
NodePtr p;
{
int storeResult;
if (p->tag != P_ATLIT ||
p->b.atlit.name == NULL ||
p->b.atlit.f.isTypeVariable ||
p->b.atlit.f.dependsOnTypeVariable) return;
if (keydatum.dptr == NULL) return;
sprintf(thevaluespace, "O0x%08x", p->b.atlit.id);
valuedatum.dptr = thevaluespace;
valuedatum.dsize = strlen(thevaluespace);
TRACE2(matchat, 1, "storing %s with key %s", ATName(p),
keydatum.dptr);
if ((storeResult = dbm_store(emDBM, keydatum, valuedatum, DBM_REPLACE)) < 0) assert(FALSE);
free(keydatum.dptr);
keydatum.dptr = writeAT(p, TRUE, FALSE);
if (keydatum.dptr == NULL) {
TRACE0(matchat, 1, "Cannot write (not figured out yet) AT");
return;
}
keydatum.dsize = strlen(keydatum.dptr);
storeResult = dbm_store(emDBM, keydatum, valuedatum, DBM_REPLACE);
if (storeResult < 0) assert(FALSE);
free(keydatum.dptr);
scheduleOutput(p->b.atlit.id);
ensureGenerate(p->b.atlit.id);
}
void defineGlobal(p, id)
register NodePtr p;
OID id;
{
OID newID = 0;
p->b.oblit.f.isManifest = TRUE;
p->b.oblit.f.writeSeparately = TRUE;
if (!bflag && p->tag == P_ATLIT) {
newID = isDuplicateAT(p);
if (newID != 0) {
p->b.atlit.id = newID;
return;
}
}
if (id == 0) {
newID = AllocateOID();
if (p->tag == P_OBLIT && ! p->b.oblit.f.immutable) {
assert(Zflag);
newID &= 0xfeffffff;
}
} else {
newID = id;
}
p->b.oblit.id = newID;
if (p->b.oblit.f.isTypeVariable) {
fprintf(stderr, "Type Variable 0x%.8x (OID 0x%08x) set writeSeparately\n",
p, p->b.oblit.id);
}
OTInsert(p, p->b.oblit.id);
if (!bflag && p->tag == P_ATLIT) {
defineAT(p);
}
}
void setStage(id, stage)
OID id;
EnvironmentStage stage;
{
Map_Insert(environmentMap, (int)id, stage);
}
extern char *builtinNames[];
static OID lookup(fPathName, fName)
char *fPathName, *fName;
{
FILE *fp;
char buffer[256], entry[256], *status, *filename;
OID oid;
Boolean found = FALSE;
int i;
if (! bflag && (!strcmp(fPathName, "Builtins") || !strcmp(fPathName, "builtins"))) {
(void) sprintf(entry, "_%sobject", fName);
for (i = 0; builtinNames[i] && strcmp(builtinNames[i], entry); i++) ;
if (builtinNames[i] != NULL) {
found = TRUE;
oid = OIDOfBuiltin(B_IT, i);
}
} else {
filename = malloc((unsigned)(strlen(emdbDirectory)+strlen(fPathName)+30));
(void) sprintf(filename, "%s/Trees/Map/%s", emdbDirectory, fPathName);
fp = fopen(filename, "r+");
if (fp == NULL) return(0);
free(filename);
status = fgets(buffer, 256, fp);
while (status != NULL) {
if (sscanf(buffer, "%[^ ] 0x%x", entry, &oid) != 2) assert(FALSE);
if (! strcmp (entry, fName)) {
found = TRUE;
break;
}
status = fgets(buffer, 256, fp);
}
if (fclose(fp) == EOF) assert(FALSE);
}
return(found ? oid : 0);
}
static Boolean install(fPathName, fName, fOID)
char *fPathName, *fName;
OID fOID;
{
FILE *fp;
char buffer[256], entry[256], *status, *filename;
OID oid;
int where;
Boolean found = FALSE;
filename = malloc((unsigned)(strlen(emdbDirectory)+strlen(fPathName)+30));
(void) sprintf(filename, "%s/Trees/Map/%s", emdbDirectory, fPathName);
fp = fopen(filename, "r+");
if (fp == NULL) {
if (errno == ENOENT) {
fp = fopen(filename, "w+");
if (fp == NULL) return(FALSE);
} else {
return(FALSE);
}
}
free(filename);
where = ftell(fp);
status = fgets(buffer, 256, fp);
while (status != NULL) {
if (sscanf(buffer, "%[^ ] 0x%x", entry, &oid) != 2) assert(FALSE);
if (! strcmp (entry, fName)) {
if (fseek(fp, (long)where, 0) == -1) assert(FALSE);
fprintf(fp, "%s 0x%08x\n", fName, fOID);
found = TRUE;
break;
}
where = ftell(fp);
status = fgets(buffer, 256, fp);
}
if (! found) {
if (fseek(fp, 0L, 2) == -1) assert(FALSE);
fprintf(fp, "%s 0x%08x\n", fName, fOID);
}
if (fclose(fp) == EOF) assert(FALSE);
return(TRUE);
}
char *makeOIDFileName(fOID)
OID fOID;
{
char *filename;
if (bflag) {
/* cheat and put them here. */
filename = (char *) malloc(100);
(void) sprintf(filename, "OID%08x.t", fOID);
} else {
filename = (char *) malloc((unsigned) strlen(emdbDirectory) + 40);
(void) sprintf(filename, "%s/Trees/Objects_%0.1x/OID%08x.t",
emdbDirectory, fOID & 0xf, fOID);
}
return(filename);
}
char *makeOIDDotoFileName(fOID)
OID fOID;
{
char *filename;
filename = (char *) malloc((unsigned) strlen(emdbDirectory) + 40);
(void) sprintf(filename, "%s/Dotos/Objects_%0.1x/OID%08x.o",
emdbDirectory, fOID & 0xf, fOID);
return(filename);
}
void doImports(p)
register NodePtr p;
{
Symbol sym;
register NodePtr q, symbolList, r, s;
char *pathName, *objectName;
OID theOID;
assert(p->tag == P_COMP);
p = p->b.comp.import;
if (p == NULL) return;
assert(p->tag == T_SEQUENCE);
Sequence_For(q, p)
assert(q->tag == P_IMPORT);
symbolList = q->b.import.syms;
assert(q->b.import.path->tag == T_STRING);
pathName = q->b.import.path->b.string.string;
Sequence_For(r, symbolList)
sym = ST_Fetch(r->b.symref.symbol);
objectName = Ident_Name(sym->itsIdent);
TRACE2(passes, 1, "Looking up %s in %s.", objectName, pathName);
theOID = lookup(pathName, objectName);
if (theOID == 0) {
ErrorMessage(r, "Name \"%s\" undefined in \"%s\"",
objectName, pathName);
} else {
if (bflag && loadedDummyBuiltins) {
Map_Delete(objectTable, (int)theOID);
Map_Delete(environmentMap, (int)theOID);
}
s = OTLookup(theOID);
sym->value.value = s;
sym->isManifest = TRUE;
sym->hasValue = TRUE;
if (s->tag == P_OBLIT) {
sym->value.CTinfo = s;
if (! bflag) {
assert(s->b.oblit.myat != NULL);
sym->value.ATinfo = s->b.oblit.myat;
} else {
sym->value.ATinfo = refToBuiltin(B_INSTAT, ANYINDEX);
}
} else if (s->tag == P_ATLIT) {
sym->value.ATinfo = refToBuiltin(B_INSTAT, SIGNATUREINDEX);
sym->value.CTinfo = refToBuiltin(B_INSTCT, SIGNATUREINDEX);
}
}
Sequence_Next
Sequence_Next
doInput();
}
void doExports(p)
register NodePtr p;
{
Symbol sym;
register NodePtr q, symbolList, r, s;
char *pathName, *objectName;
OID theOID;
assert(p->tag == P_COMP);
p = p->b.comp.export;
assert(isASequence(p));
Sequence_For(q, p)
assert(q->tag == P_EXPORT);
symbolList = q->b.export.syms;
assert(q->b.export.path->tag == T_STRING);
pathName = q->b.export.path->b.string.string;
Sequence_For(r, symbolList)
sym = ST_Fetch(r->b.symref.symbol);
objectName = Ident_Name(sym->itsIdent);
s = GETVALUE(sym->value.value);
if (s == NULL) {
ErrorMessage(r, "Exported symbol \"%s\" is not manifest",
ST_SymbolName(sym));
} else if (s->tag != P_ATLIT && s->tag != P_OBLIT) {
ErrorMessage(r, "Implementation restriction:\n\
\tonly object literals and type literals can be exported");
} else {
assert(s->b.atlit.f.isManifest || s->b.atlit.f.dependsOnTypeVariable);
if (bflag) {
prepareBuiltinForOutput(s, objectName);
} else {
if (s->b.atlit.id == 0) {
s->b.atlit.id = AllocateOID();
OTInsert(s, s->b.atlit.id);
}
}
theOID = s->b.atlit.id;
TRACE3(passes, 1, "Installing %s (oid 0x%08x) in %s.",
objectName, theOID, pathName);
if (! install(pathName, objectName, theOID)) {
ErrorMessage(r, "Could not install \"%s\" in \"%s\"",
objectName, pathName);
} else {
storeObject(theOID);
}
}
Sequence_Next
Sequence_Next
doOutput();
if (bflag) {
Map_Destroy(translateOIDMap);
translateOIDMap = NULL;
}
}
ensureDirectory(name)
char *name;
{
struct stat buf;
int res;
if ((res = stat(name, &buf)) < 0) {
if (mkdir(name, 0777) < 0) {
fprintf(stderr, "Can't create directory %s\n", name);
numberOfSemanticErrors++;
}
res = stat(name, &buf);
}
if (res < 0) {
fprintf(stderr, "Couldn't stat directory %s\n", name);
perror("mkdir");
} else {
if (! (buf.st_mode & S_IFDIR)) {
fprintf(stderr, "%s should be, but is not, a directory\n", name);
}
}
}
initializeDataBaseFiles()
{
char pname[1024], *s;
struct stat buf;
ensureDirectory(emdbDirectory);
sprintf(pname, "%s/initialized", emdbDirectory);
if (stat(pname, &buf) >= 0) return;
sprintf(pname, "%s/DB", emdbDirectory);
ensureDirectory(pname);
sprintf(pname, "%s/Trees", emdbDirectory);
ensureDirectory(pname);
sprintf(pname, "%s/Trees/Map", emdbDirectory);
ensureDirectory(pname);
sprintf(pname, "%s/Dotos", emdbDirectory);
ensureDirectory(pname);
for (s = "0123456789abcdef"; *s; s++) {
sprintf(pname, "%s/Trees/Objects_%c", emdbDirectory, *s);
ensureDirectory(pname);
sprintf(pname, "%s/Dotos/Objects_%c", emdbDirectory, *s);
ensureDirectory(pname);
}
sprintf(pname, "%s/initialized", emdbDirectory);
close(open(pname, O_RDWR | O_CREAT, 0777));
}